#include "CEnemy.h"
#include "CRandom.h"
#include "MainLayer.h"
#include "GamePlayScene.h"

USING_NS_CC;

CEnemy::CEnemy():
	__enemyParams(),
	__pAnimationAction(NULL),
	__currentHealth(0)
{
}

CEnemy::CEnemy(CEnemyParams enemyParams) :
	__enemyParams(enemyParams),
	__pAnimationAction(NULL),
	__currentHealth(0)
{
}

/**
 * This method adds enemie's animations to cache,
 * sets the enemy health and reorders the sprite to position
 * bigger enemies behind smaller.
 *
 * @param pSpriteSheet This parameter is created and released by the MainLayer.
 * @return true if the sprite was initialized without problems, false otherwise.
 */
bool
CEnemy::init(cocos2d::CCSpriteBatchNode* pSpriteSheet, b2World* pWorld)
{
	// Set the enemie's frame name based on its type and size.
	char frameNamePrefix[512];
	memset(frameNamePrefix,NULL,sizeof(frameNamePrefix));
	sprintf(frameNamePrefix,"enemyT%dS%dNormal",static_cast<int>(__enemyParams._type), static_cast<int>(__enemyParams._size));
	if(!CAnimatedObject::init(frameNamePrefix, pSpriteSheet, pWorld))
	{
		return false;
	}

	//Load different animations to cache.
	addAnimation("Normal");
	addAnimation("Hit");
	addAnimation("Dmg");

	this->setTag(3);
	__currentHealth = __enemyParams._health;

	// Move bigger enemies behind smaller.
	_pSpriteSheet->reorderChild(this, CEnemyParams::sizeCount - 1 - static_cast<int>(__enemyParams._size));

	return true;
}

/**
 * Sets animation parameters based on provided State parameter
 * and calls addAnimation() to store the animation in cache.
 *
 * @param state Suffix for enemy animation frame, e.g. "Normal", "Hit", "Dmg" (enemyT1S1Normal)
 */
void
CEnemy::addAnimation(char* state)
{
	char animationName[512];
	memset(animationName,0,sizeof(animationName));
	sprintf(animationName,"enemyT%dS%d%s", static_cast<int>(__enemyParams._type), static_cast<int>(__enemyParams._size),state);

	CAnimationProperties* animProp = new CAnimationProperties();
	animProp->_animationName =  animationName;
	animProp->_frameCount = 3;
	animProp->_delay = 0.1f;
	CAnimatedObject::addAnimation(animProp);
}

/**
 * Set enemy's starting position, run the CCMoveTo action and start the animation.
 */
void
CEnemy::start()
{
	CCSize enemySize = this->boundingBox().size;
	CCSize winSize = CCDirector::sharedDirector()->getWinSize();

	float x = winSize.width + enemySize.width / 2.0f;
	float y = (float)(__enemyParams._startingPosition % (int)(winSize.height - enemySize.height)) + enemySize.height / 2.0f;

	this->setPosition(ccp(x, y));

	float duration = winSize.width / __enemyParams._speed;
	x = -this->boundingBox().size.width - 5;
	CCFiniteTimeAction* actionMove = CCMoveTo::actionWithDuration(duration, ccp(x, y));
	this->runAction(actionMove);
	anim("Normal");
}

/**
 * Reduce enemie's health, update score and play adequate animation.
 *
 * @param damage This value will be subtracted from __currentHealth parameter.
 */
void
CEnemy::collision(float damage)
{
	__currentHealth -= damage;
	if(__currentHealth <= 0 )
	{
		// Remove the enemy and update the score.
		float points = __enemyParams._health;
		CCScene* scene = CCDirector::sharedDirector()->getRunningScene();
		MainLayer* mainLayer = static_cast<MainLayer*>(scene->getChildByTag(GamePlayScene::mainLayerTag));
		mainLayer->updateScore(points);

		this->setDelete(true);
		__currentHealth = 0;
	}
	else
	{
		// Play the animation according to enemie's current health.
		if(__currentHealth / __enemyParams._health > 0.2f)
		{
			anim("Hit");
			this->runAction(CCSequence::actions(CCDelayTime::actionWithDuration(0.2f),
							CCCallFunc::actionWithTarget(this, callfunc_selector(CEnemy::restoreNormal)),
							NULL));
		}
		else
		{
			anim("Dmg");
		}
	}
}

/**
 * Change enemie's animation according to the state parameter.
 * @param state Suffix for enemy animation name, e.g. "Normal", "Hit", "Dmg" (enemyT1S1Normal)
 */
void
CEnemy::anim(char* state)
{
	if(__pAnimationAction)
	{
		this->stopAction(__pAnimationAction);
	}
	char animationName[512];
	memset(animationName,0,sizeof(animationName));
	sprintf(animationName,"enemyT%dS%d%s", static_cast<int>(__enemyParams._type), static_cast<int>(__enemyParams._size),state);

	//Load animation
	CCAnimation* pAnimation = CCAnimationCache::sharedAnimationCache()->animationByName(animationName);
	__pAnimationAction = CCRepeatForever::actionWithAction(CCAnimate::actionWithAnimation(pAnimation));
	this->runAction(__pAnimationAction);
}

/**
 * This method is called after the hit animation was played.
 */
void
CEnemy::restoreNormal()
{
	anim("Normal");
}

float
CEnemy::getCurrentHealth()
{
	return __currentHealth;
}

float
CEnemy::getBaseHealth()
{
	return __enemyParams._health;
}

void
CEnemy::createBoxBody()
{
    b2BodyDef spriteBodyDef;
    spriteBodyDef.type = b2_dynamicBody;
    spriteBodyDef.active = true;
    float x = this->getPosition().x / P2M;
    float y = this->getPosition().y / P2M;
    spriteBodyDef.position.Set(x, y);
    spriteBodyDef.userData = this;
    _pBody = _pWorld->CreateBody(&spriteBodyDef);
}
